package model.dao;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import model.dao.exception.ConstraintViolationException;
import model.dao.exception.UniqueViolationException;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;



public abstract class AbstractDAO<T> {

	

	private static Logger logger = Logger.getLogger(AbstractDAO.class);
	protected JdbcTemplate jdbcTemplate;

	public AbstractDAO() {
		
	    this.setDataSource(DataSourceFactory.getDataSource());

	}

	public void setDataSource(DataSource dataSource) {
		jdbcTemplate = new JdbcTemplate(dataSource);
		MySQLErrorCodesTransalator tr = new MySQLErrorCodesTransalator();
		tr.setDataSource(dataSource);
		jdbcTemplate.setExceptionTranslator(tr);
	}

	public T selectByPrimaryKey(Long key) {
		String query = getQueryFindByPrimaryKey();
		logger.debug(query);
		return jdbcTemplate.queryForObject(query, new Object[] { key },
				getMapper());
	}

	private String getQueryFindByPrimaryKey() {
		return "Select * from " + getTableName() + " where " + getIdField()
				+ " = ?";
	}

	public abstract T store(T object);

	public Collection<T> store(Collection<T> object){
		Collection<T> col = new ArrayList<T>(); 
		for (T t : object) {
			col.add(store(t));
		}
		return col;
	}

	protected abstract RowMapper<T> getMapper();

	protected abstract String getTableName();

	protected abstract String getIdField();

	public Collection<T> getAll() {
		return jdbcTemplate.query("select * from " + getTableName(),
				getMapper());
	}

	public Collection<T> getAllOrderBy(String field) {
		return jdbcTemplate.query("select * from " + getTableName()
				+ " order by " + field, getMapper());
	}

	private class MySQLErrorCodesTransalator extends
			SQLErrorCodeSQLExceptionTranslator {
		@Override
		public DataAccessException translate(String task, String sql,
				SQLException ex) {
			AbstractDAO.logger.debug(ex);
			return super.translate(task, sql, ex);
		}

		protected DataAccessException customTranslate(String task, String sql,
				SQLException sqlex) {
			if (sqlex.getMessage().contains("unique")) {
				return new UniqueViolationException(parse(sqlex.getMessage()));
			} else if (sqlex.getMessage().startsWith("[SQLITE_CONSTRAINT]")) {
				return new ConstraintViolationException(sqlex);
			}
			return null;
		}

		private String parse(String message) {
			Pattern p = Pattern.compile("(?<=column)(.*)(?=is not unique)");
			Matcher m = p.matcher(message);
			m.find();
			String field = m.toMatchResult().group();
			logger.debug("Match: " + field);
			return field;
		}

	}
}
